// ------------------------------------------------------------------------------------------------
// File   : DX9PixelShaderManager.h
// Date   : 2012-08-01
// Author : Weng xiao yi
// Descr. : 
//
// ------------------------------------------------------------------------------------------------

#ifndef OY_DX9PIXELSHADERMGR_H
#define OY_DX9PIXELSHADERMGR_H

#include <map>
#include <windows.h>



enum EDX9PSMaterials
{
	ePSMaterial_Default,
	ePSMaterial_ConstantColor,
	ePSMaterial_AfterEffect,

	ePSMaterial_AdvancedWater,
	ePSMaterial_SpaceBump,

	ePSMaterial_SoftParticle,
	ePSMaterial_DynamicWeather,

	//Below is Assemble Shader, if using HLSL, please add it upper
	ePSMaterial_Shadowmap,
};



// Declaration of the basic class attributes
#define DX9PS_DECLARE_CLASS(_class_, _id_)                              \
	public:                                                             \
	_class_(void) { Reset(); }                                          \
	inline ULONG64 GetKey(void)        { return stKey.ulKey; }          \
	inline UCHAR   GetMaterialID(void) { return stKey.ulMaterialID; }   \
	inline void    Reset(void)         { stKey.ulKey = 0; stKey.ulMaterialID = _id_; }

// ------------------------------------------------------------------------------------------------
// FORWARD DECLARATIONS
// ------------------------------------------------------------------------------------------------
class DX9PixelShader;
struct ID3DXConstantTable;

// DX9PixelShaderManager class definition ------------------------

class DX9PixelShaderManager
{
public:

	// Please increment DX9_SHADER_DB_VERSION (DX9ShaderDatabase.cpp) for any feature change (not necessary if adding a new material or variable.)

	class DX9PSFeature
	{
	public:

		virtual inline ULONG64 GetKey(void) = 0;
		virtual inline UCHAR   GetMaterialID(void) = 0;

		const char* BuildFeatureDefinition(char *_szFeatureDefinition);

		virtual BOOL IsExtended(void) { return 0; }

		virtual void AddSpecificFeatures(CHAR* _szFeatureDefinition) { };

		virtual BOOL UseAssemble(void) { return 0; }
		virtual const CHAR* GetAssembleShader(void) { return NULL; }
	};

	class DX9PSFeatureDefault : public DX9PSFeature
	{
		DX9PS_DECLARE_CLASS(DX9PSFeatureDefault, ePSMaterial_Default);

		union
		{
			struct
			{
				ULONG64 ulShaderVer					: 6;	// Shader version
				ULONG64 ulMaterialID                : 8;    // Material used for shader setup
				ULONG64 ulReserved                  : 50;   // Used by material to define the features
			};
			ULONG64 ulKey;
		} stKey;

		static void PreCache() { }
	};

	class DX9PSFeatureConstantColor : public DX9PSFeature
	{
		DX9PS_DECLARE_CLASS(DX9PSFeatureConstantColor, ePSMaterial_ConstantColor);

		union
		{
			struct
			{
				ULONG64 ulShaderVer					: 6;	// Shader version
				ULONG64 ulMaterialID                : 8;    // Material used for shader setup
				ULONG64 ulReserved                  : 50;   // Used by material to define the features
			};
			ULONG64 ulKey;
		} stKey;

		void AddSpecificFeatures(CHAR *_szFeatureDefinition);
		static void PreCache() { }
	};

	class DX9PSFeatureAfterEffect : public DX9PSFeature
	{
		DX9PS_DECLARE_CLASS(DX9PSFeatureAfterEffect, ePSMaterial_AfterEffect);

		union
		{
			struct
			{
				ULONG64 ulShaderVer					: 6;	// Shader version
				ULONG64 ulMaterialID                : 8;    // Material used for shader setup
				ULONG64 ulEffectId                  : 8;    // After Effect Id
				ULONG64 ulEffectSubType             : 4;    // After Effect sub type
				ULONG64 ulSamplesCount              : 4;    // Number of samples
				ULONG64 ulReserved                  : 34;
			};
			ULONG64 ulKey;
		} stKey;

		void AddSpecificFeatures(CHAR* _szFeatureDefinition);
		static void PreCache();
	};


	class DX9PSFeatureAdvancedWater : public DX9PSFeature
	{
		DX9PS_DECLARE_CLASS(DX9PSFeatureAdvancedWater, ePSMaterial_AdvancedWater);

		union
		{
			struct
			{
				ULONG64 ulShaderVer					: 6;	// Shader version
				ULONG64 ulMaterialID                : 8;    // Material used for shader setup
				ULONG64 ulWaterPassID               : 4;    // Water render pass Id
				ULONG64 ulAssemble					: 1;
				ULONG64 ulReserved                  : 45;
			};
			ULONG64 ulKey;
		} stKey;

		void AddSpecificFeatures(CHAR* _szFeatureDefinition);
		virtual const CHAR* GetAssembleShader();
		virtual BOOL UseAssemble(void)
		{
			return (stKey.ulAssemble == 1);
		}
		static void PreCache();
	};

	class DX9PSFeatureShadowmap : public DX9PSFeature
	{
		DX9PS_DECLARE_CLASS(DX9PSFeatureShadowmap, ePSMaterial_Shadowmap);
		union
		{
			struct
			{
				ULONG64 ulShaderVer					: 6;	// Shader version
				ULONG64 ulMaterialID                : 8;    // Material used for shader setup
				ULONG64 ulshadowPassID              : 4;    // shadow map render pass Id
				ULONG64 ulAssemble					: 1;
				ULONG64 ulReserved                  : 45;
			};
			ULONG64 ulKey;
		} stKey;

		//void AddSpecificFeatures(CHAR* _szFeatureDefinition);
		virtual const CHAR* GetAssembleShader();
		virtual BOOL UseAssemble(void)
		{
			return (stKey.ulAssemble == 1);
		}
		static void PreCache();
	};

	class DX9PSFeatureSpaceBump : public DX9PSFeature
	{
		DX9PS_DECLARE_CLASS(DX9PSFeatureSpaceBump, ePSMaterial_SpaceBump);

		union
		{
			struct
			{
				ULONG64 ulShaderVer					: 6;	// Shader version
				ULONG64 ulMaterialID                : 8;    // Material used for shader setup
				ULONG64 ulReserved                  : 50;   // Used by material to define the features
			};
			ULONG64 ulKey;
		} stKey;
		static void PreCache();
	};

	class DX9PSFeatureDynamicWeather : public DX9PSFeature
	{
		DX9PS_DECLARE_CLASS(DX9PSFeatureDynamicWeather, ePSMaterial_DynamicWeather);

		union
		{
			struct
			{
				ULONG64 ulShaderVer					: 6;	// Shader version
				ULONG64 ulMaterialID                : 8;    // Material used for shader setup
				ULONG64 ulReserved                  : 50;   // Used by material to define the features
			};
			ULONG64 ulKey;
		} stKey;
		static void PreCache();
	};


	class DX9PSFeatureSoftParticle : public DX9PSFeature
	{
		DX9PS_DECLARE_CLASS(DX9PSFeatureSoftParticle, ePSMaterial_SoftParticle);

		union
		{
			struct
			{
				ULONG64 ulShaderVer					: 6;	// Shader version
				ULONG64 ulMaterialID                : 8;    // Material used for shader setup
				ULONG64 ulReserved                  : 50;   // Used by material to define the features
			};
			ULONG64 ulKey;
		} stKey;
		static void PreCache();
	};

	DX9PixelShaderManager();
	~DX9PixelShaderManager();

	inline static DX9PixelShaderManager* GetInstance(void) 
	{ 
		static DX9PixelShaderManager sm_Instance;
		return &sm_Instance;
	}

	void Shutdown(void);

	void InitShadersTable(void);
	void UnloadAll(void);
	void UnloadAllShaders(void);

	void BuildShaderDefinition(DX9PSFeature* _poFeatures, char *_szShaderDefinition);
	DX9PixelShader* GetShader(DX9PSFeature* _poFeatures);

	BOOL GenerateShader(DX9PSFeature* _poFeatures);
	void AddShader(const ULONG64& _ulKey, DX9PixelShader* _pShader);
	void AddCreateShader(const ULONG64& _ulKey, const void* _pCode, ID3DXConstantTable* _pConstantTable);
	void PreLoadShader(const ULONG64& _ulKey, void* _pCode);
	DX9PixelShader* CreateShader(const ULONG64& _ulKey, const void* _pCode, ID3DXConstantTable* _pConstantTable, CHAR* _szName);

	inline void ResetDefinitionBuffers() { m_szFeatures[0] = NULL; }
	inline CHAR *GetFeatureDefinitionBuffer()          { return m_szFeatures; }

	// data types
	typedef std::map<INT64, DX9PixelShader*> MapPixelShader;

private: // members

	MapPixelShader                 m_mapLoadedShaders;

	// definition buffers
	char m_szFeatures[4096];
};

#define DX9GetPixelShaderManager() DX9PixelShaderManager::GetInstance()

#endif //OY_DX9PIXELSHADERMGR_H
